// ============================================================================
// 依赖注入容器
// ============================================================================

/**
 * 服务工厂函数类型
 */
export type ServiceFactory<T = any> = () => T

/**
 * 服务生命周期类型
 */
export type ServiceLifetime = 'singleton' | 'transient'

/**
 * 服务注册信息
 */
interface ServiceRegistration<T = any> {
  factory: ServiceFactory<T>
  lifetime: ServiceLifetime
  instance?: T
}

/**
 * 依赖注入容器
 * 提供服务注册、解析和生命周期管理
 */
export class Container {
  private services = new Map<string, ServiceRegistration>()
  private resolving = new Set<string>()

  /**
   * 注册单例服务
   */
  registerSingleton<T>(name: string, factory: ServiceFactory<T>): void {
    this.register(name, factory, 'singleton')
  }

  /**
   * 注册瞬态服务
   */
  registerTransient<T>(name: string, factory: ServiceFactory<T>): void {
    this.register(name, factory, 'transient')
  }

  /**
   * 注册服务实例
   */
  registerInstance<T>(name: string, instance: T): void {
    this.services.set(name, {
      factory: () => instance,
      lifetime: 'singleton',
      instance
    })
  }

  /**
   * 获取服务实例
   */
  get<T>(name: string): T {
    const registration = this.services.get(name)
    
    if (!registration) {
      throw new Error(`Service '${name}' is not registered`)
    }

    // 检查循环依赖
    if (this.resolving.has(name)) {
      throw new Error(`Circular dependency detected for service '${name}'`)
    }

    // 单例模式：返回已存在的实例
    if (registration.lifetime === 'singleton' && registration.instance) {
      return registration.instance
    }

    try {
      this.resolving.add(name)
      
      // 创建新实例
      const instance = registration.factory()
      
      // 单例模式：缓存实例
      if (registration.lifetime === 'singleton') {
        registration.instance = instance
      }
      
      return instance
      
    } finally {
      this.resolving.delete(name)
    }
  }

  /**
   * 检查服务是否已注册
   */
  has(name: string): boolean {
    return this.services.has(name)
  }

  /**
   * 获取所有已注册的服务名称
   */
  getServiceNames(): string[] {
    return Array.from(this.services.keys())
  }

  /**
   * 清除所有服务注册
   */
  clear(): void {
    this.services.clear()
    this.resolving.clear()
  }

  /**
   * 移除服务注册
   */
  remove(name: string): boolean {
    return this.services.delete(name)
  }

  /**
   * 创建子容器
   */
  createChild(): Container {
    const child = new Container()
    
    // 复制父容器的服务注册
    for (const [name, registration] of this.services) {
      child.services.set(name, {
        factory: registration.factory,
        lifetime: registration.lifetime
        // 不复制实例，子容器有自己的实例
      })
    }
    
    return child
  }

  /**
   * 注册服务的私有方法
   */
  private register<T>(name: string, factory: ServiceFactory<T>, lifetime: ServiceLifetime): void {
    if (this.services.has(name)) {
      throw new Error(`Service '${name}' is already registered`)
    }

    this.services.set(name, {
      factory,
      lifetime
    })
  }
}

/**
 * 装饰器：标记类为可注入的服务
 */
export function Injectable(name?: string) {
  return function <T extends new (...args: any[]) => any>(constructor: T) {
    const serviceName = name || constructor.name
    
    // 可以在这里添加元数据或其他逻辑
    Object.defineProperty(constructor, 'serviceName', {
      value: serviceName,
      writable: false,
      enumerable: false
    })
    
    return constructor
  }
}

/**
 * 装饰器：标记构造函数参数为依赖注入
 * 注意：需要安装 reflect-metadata 包才能使用
 */
export function Inject(serviceName: string) {
  return function (target: any, _propertyKey: string | symbol | undefined, parameterIndex: number) {
    // 简化版本，不使用 reflect-metadata
    // 可以在需要时扩展为完整的元数据支持
    if (!target.__injectTokens) {
      target.__injectTokens = []
    }
    target.__injectTokens[parameterIndex] = serviceName
  }
}

/**
 * 服务定位器模式的简单实现
 * 用于在无法使用依赖注入的地方获取服务
 */
export class ServiceLocator {
  private static container: Container | null = null

  /**
   * 设置全局容器
   */
  static setContainer(container: Container): void {
    this.container = container
  }

  /**
   * 获取服务实例
   */
  static get<T>(name: string): T {
    if (!this.container) {
      throw new Error('Container is not set. Call ServiceLocator.setContainer() first.')
    }
    
    return this.container.get<T>(name)
  }

  /**
   * 检查服务是否存在
   */
  static has(name: string): boolean {
    if (!this.container) {
      return false
    }
    
    return this.container.has(name)
  }
}
